package models

import (
	"chatproject/utils"
	"context"
	"encoding/json"
	"fmt"
	"github.com/gorilla/websocket"
	"gopkg.in/fatih/set.v0"
	"gorm.io/gorm"
	"net"
	"net/http"
	"strconv"
	"sync"
)

const (
	PublishKey = "websocket"
)

// Message 消息
type Message struct {
	gorm.Model
	FromId   int64 //发送者
	TargetId int64 //接受者
	Type     int   //消息类型（群聊，私聊，广播）
	Media    int   //文字/图片/音频
	Content  string
	Pic      string
	Url      string
	Desc     string
	Amount   int //其他数字统计
}

func (table *Message) TableName() string {
	return "message"
}

type Node struct {
	Conn      *websocket.Conn
	DataQueue chan []byte
	Groupsets set.Interface
}

// clientMap 映射关系
var clientMap = make(map[int64]*Node)

// rwLocker读写锁
var rwLock sync.RWMutex

// Chat 需要发送者ID 接受者ID 消息类型 发送内容 发送类型
func Chat(writer http.ResponseWriter, request *http.Request) {
	//1--获取参数并校验token等合法性
	//token := query.Get("token")
	query := request.URL.Query()
	id := query.Get("userId")
	userId, err := strconv.ParseInt(id, 10, 64)
	if err != nil {
		fmt.Println(err)
	}
	tid := query.Get("targetId")

	targetId, _ := strconv.ParseInt(tid, 10, 64)
	//content := query.Get("content")
	//messageType := query.Get("type")
	isValida := true //(checkToken 待补充)
	conn, err := (&websocket.Upgrader{
		CheckOrigin: func(r *http.Request) bool {
			return isValida
		},
	}).Upgrade(writer, request, nil)
	if err != nil {
		fmt.Println(err)
		return
	}
	//2--获取连接
	node := &Node{
		Conn:      conn,
		DataQueue: make(chan []byte, 50),
		Groupsets: set.New(set.ThreadSafe),
	}
	//3--用户关系
	//4--绑定userid和node并加锁
	rwLock.Lock()
	clientMap[userId] = node
	rwLock.Unlock()
	//5--完成发送逻辑
	go sendProc(node)
	//6--完成接受逻辑
	go recvProc(node)
	sendMsg(targetId, []byte("欢迎进入聊天室"))
}
func sendProc(node *Node) {
	for {
		select {
		case data := <-node.DataQueue:
			err := node.Conn.WriteMessage(websocket.TextMessage, data)
			if err != nil {
				fmt.Println(err)
				return
			}
		}
	}
}
func recvProc(node *Node) {
	for {
		_, data, err := node.Conn.ReadMessage()
		if err != nil {
			fmt.Println(err)
			return
		}
		broadMsg(data)
		fmt.Println("[ws]<<<<<<<<<", data)
	}
}

var udpsendChan = make(chan []byte, 1024)

func broadMsg(data []byte) {
	udpsendChan <- data
}
func init() {
	go updSendProc()
	go udpRecvProc()
}

// 完成数据发送协程
func updSendProc() {
	con, err := net.DialUDP("udp", nil, &net.UDPAddr{
		IP:   net.IPv4(127, 0, 0, 1),
		Port: 3000,
	})
	if err != nil {
		fmt.Println(err)
		return
	}
	defer func() {
		result := con.Close()
		fmt.Println(result)
	}()
	for {
		select {
		case data := <-udpsendChan:
			_, err := con.Write(data)
			if err != nil {
				fmt.Println(err)
				return
			}

		}
	}
}

// 完成数据接收协程
func udpRecvProc() {
	con, err := net.ListenUDP("udp", &net.UDPAddr{
		IP:   net.IPv4zero,
		Port: 3000,
	})
	if err != nil {
		fmt.Println(err)
		return
	}
	defer func() {
		result := con.Close()
		fmt.Println(result)
	}()
	for {
		var buf [512]byte
		n, err := con.Read(buf[0:])
		if err != nil {
			fmt.Println(err)
			return
		}
		dispatch(buf[0:n], con)
	}
}

// 后端调度逻辑处理
func dispatch(data []byte, conn *net.UDPConn) {
	msg := Message{}
	err := json.Unmarshal(data, &msg)
	if err != nil {
		fmt.Println(err)
		return
	}
	switch msg.Type {
	case 1:
		sendMsg(msg.TargetId, data)
		//case 2: sendGroupMsg()
		//case 3: sendALLMsg()
		//case 4:
		//
	}
}

func sendMsg(targetId int64, msg []byte) {
	rwLock.RLock()
	node, ok := clientMap[targetId]
	rwLock.RUnlock()
	if ok {
		node.DataQueue <- msg
	}
}

// Publish  发布消息到redis
func Publish(ctx context.Context, channel string, message string) error {
	var err error
	fmt.Println("Publish", message)
	err = utils.RDB.Publish(ctx, channel, message).Err()
	if err != nil {
		fmt.Println(err)
	}
	return err
}

// Subscribe 订阅redis中的消息
func Subscribe(ctx context.Context, channel string) (string, error) {
	sub := utils.RDB.Subscribe(ctx, channel)
	fmt.Println("Subscribe", ctx)
	message, err := sub.ReceiveMessage(ctx)
	if err != nil {
		println(err)
		return "", err
	}
	fmt.Println("Subscribe", message.Payload)
	return message.Payload, err
}
